package io.gitee.zhangbinhub.acp.boot.component

import io.gitee.zhangbinhub.acp.boot.constant.AcpCoreConstant
import io.gitee.zhangbinhub.acp.boot.job.AcpJob
import io.gitee.zhangbinhub.acp.boot.log.LogAdapter
import org.noear.solon.Solon
import org.noear.solon.scheduling.annotation.Scheduled
import org.noear.solon.scheduling.simple.JobManager

/**
 * 定时任务处理器
 *
 * @since JDK 17
 */
class AcpTimerTaskSchedulerCtrl(private val logAdapter: LogAdapter) {
    /**
     * 启动定时任务
     */
    fun startSchedule() {
        startJobs()
        Solon.cfg().onChange { key, _ ->
            if (key == AcpCoreConstant.SCHEDULE_PROPERTIES_AUTO_RESTART) {
                if (Solon.cfg().getBool(AcpCoreConstant.SCHEDULE_PROPERTIES_AUTO_RESTART, false)) {
                    stopJobs()
                    startJobs()
                }
            }
        }
    }

    /**
     * 停止定时任务
     */
    fun stopSchedule() {
        stopJobs()
    }

    private fun startJobs() {
        logAdapter.info("start scheduled jobs...")
        JobManager.getInstance().let { jobManager ->
            if (!jobManager.isStarted) {
                jobManager.start()
            }
            Solon.context().getBeansMapOfType(AcpJob::class.java).forEach { (name, job) ->
                if (!jobManager.jobExists(name)) {
                    val prop = Solon.cfg().getProp("${AcpCoreConstant.SCHEDULE_PROPERTIES_PREFIX}.${name}")
                    if (prop.isNotEmpty()) {
                        Scheduled(
                            name = name,
                            cron = prop.get("cron", ""),
                            zone = prop.get("zone"),
                            initialDelay = prop.getLong("initialDelay", 0L),
                            fixedRate = prop.getLong("fixedRate", 0L),
                            fixedDelay = prop.getLong("fixedDelay", 0L),
                            enable = prop.getBool("enable", true)
                        ).apply {
                            logAdapter.info("start scheduled job [$name][${job.javaClass.canonicalName}]: $this")
                            jobManager.jobAdd(name, this, job)
                        }
                    }
                }
            }
        }
        logAdapter.info("start scheduled jobs end!")
    }

    private fun stopJobs() {
        logAdapter.info("stop all scheduled jobs...")
        JobManager.getInstance().let { jobManager ->
            Solon.context().getBeansMapOfType(AcpJob::class.java).forEach { (name, job) ->
                logAdapter.info("stop scheduled job [$name][${job.javaClass.canonicalName}]")
                jobManager.jobRemove(name)
            }
            if (jobManager.isStarted) {
                jobManager.stop()
            }
        }
        logAdapter.info("stop all scheduled jobs end!")
    }
}
